package com.neuralnetwork.sample.util;

import java.awt.Color;
import java.awt.Graphics2D;
import java.awt.image.BufferedImage;
import java.io.File;
import java.util.ArrayList;
import java.util.List;

import javax.imageio.ImageIO;

import com.neuralnetwork.sample.neuralnetwork.Network;

public class ImageSplitUtil {
	public static Network network = new Network(new int[]{28*28,30,10});
	
	public static List<Boolean> findHorizonBorders(BufferedImage src){
		int imageWidth = src.getWidth();
		List<Boolean> isBorders = new ArrayList<>();
		for (int i=0;i<imageWidth;i++) {
			isBorders.add(isVerticalWhite(src, i));
			//System.out.println(isBorders.get(i));
		}	
		return isBorders;
	}
	
	public static List<Boolean> findVerticalBorders(BufferedImage src){
		int imageHeight = src.getHeight();
		List<Boolean> isBorders = new ArrayList<>();
		for (int i=0;i<imageHeight;i++) {
			isBorders.add(isHorizonWhite(src, i));
			//System.out.println(isBorders.get(i));
		}	
		return isBorders;
	}
	
	public static List<BufferedImage> splitImage(BufferedImage src){
		int imageWidth = src.getWidth();
		List<Boolean> isBorders = new ArrayList<>();
		for (int i=0;i<imageWidth;i++) {
			isBorders.add(isVerticalWhite(src, i));
			//System.out.println(isBorders.get(i));
		}		
		return returnSplitedImages(src,isBorders);
	}
	
	public static String recogImage(BufferedImage src) throws Exception{
		String result = "";
		List<BufferedImage> images = splitImage(src);	
		saveImages(images);
		for (BufferedImage img:images) {
			result+=recogSingleImage(img);
        }
		return result;
	}
	
	public static String recogSingleImage(BufferedImage src) throws Exception{
		int digit = network.predict(ImageUtil.getInstance().getGrayMatrixFromBufferedImage(src));
        if(digit == -1){
        	throw new Exception("Recognize failed.");
        }else {
        	System.out.println("JerryDebug:Single:"+digit);
        	return ""+digit;
        }
	}
	
	private static boolean isVerticalWhite(BufferedImage src, int pos) {
	    BufferedImage convertedImg = new BufferedImage(src.getWidth(), src.getHeight(), BufferedImage.TYPE_INT_RGB);
	    convertedImg.getGraphics().drawImage(src, 0, 0, null);
		// 调用检查某条垂直线是否是纯白线
        for (int j=0;j<convertedImg.getHeight();j++) {
        	Object data = convertedImg.getRaster().getDataElements(pos, j, null);
        	int r = convertedImg.getColorModel().getRed(data);
            int g = convertedImg.getColorModel().getGreen(data);
            int b = convertedImg.getColorModel().getBlue(data);
            //System.out.println(r+":"+g+":"+b);
        	if (r<120&&g<120&&b<120) return false;
        }        
		return true;
	}
	
	private static boolean isHorizonWhite(BufferedImage src, int vpos) {
		BufferedImage convertedImg = new BufferedImage(src.getWidth(), src.getHeight(), BufferedImage.TYPE_INT_RGB);
	    convertedImg.getGraphics().drawImage(src, 0, 0, null);		
		// 调用检查某条水平线是否是纯白线
        for (int i=0;i<convertedImg.getWidth();i++) {
        	Object data = convertedImg.getRaster().getDataElements(i, vpos, null);
        	int r = convertedImg.getColorModel().getRed(data);
            int g = convertedImg.getColorModel().getGreen(data);
            int b = convertedImg.getColorModel().getBlue(data);
            System.out.println(r+":"+g+":"+b);
        	if (r<120&&g<120&&b<120) return false;
        }        
		return true;
	}
	
	public static BufferedImage clipImageVeticalBlank(BufferedImage src){
		List<Boolean> verticalBorders = findVerticalBorders(src);
		int starty = findStartBorder(verticalBorders);
		int height = findEndBorder(verticalBorders)-starty;
		BufferedImage img = src.getSubimage (0,starty , src.getWidth(), height);
		return img;
	}
	
	private static List<BufferedImage> returnSplitedImages(BufferedImage src,List<Boolean> isBorders){
		List<BufferedImage> results = new ArrayList<>();
		// 根据是否纯白线数据分割图像，返回字符图像列表
		for (int i=0;i<isBorders.size();i++) {
			int startx = findStartBorder(isBorders,i);
			int endx = findEndBorder(isBorders,i);
			int width = endx-startx;
			if (startx>0&&endx>0&&endx>startx) {
				BufferedImage img = src.getSubimage (startx, 0, width, src.getHeight());
				if (width<28) {
					BufferedImage image = new BufferedImage(28, src.getHeight(), BufferedImage.TYPE_INT_RGB);
		            //获取画笔
		            Graphics2D graphics = image.createGraphics();
		            //将Image对象画在画布上,最后一个参数,ImageObserver:接收有关 Image 信息通知的异步更新接口,没用到直接传空
		            graphics.setColor(Color.WHITE);
		            graphics.fillRect(0, 0, 28, src.getHeight());   // 矩形填充

		            graphics.drawImage(img, (28-width)/2, 0,null);
		            //一定要释放资源
		            graphics.dispose();
		            results.add(clipImageVeticalBlank(image));
				}else {
					results.add(img);
				}
				i = endx;
			}
		}
		return results;
	}
	
	public static List<Integer> returnSplitedBorders(List<Boolean> isBorders){
		List<Integer> results = new ArrayList<>();
		for (int i=0;i<isBorders.size();i++) {
			int startx = findStartBorder(isBorders,i);
			int endx = findEndBorder(isBorders,i);
			if (startx>0&&endx>0&&endx>startx) {
				results.add(startx);
				results.add(endx);
				i = endx;
			}
		}
		System.out.println("JerryDebug:vBorders2:size:"+results.size());
		for (Integer i:results) {
			System.out.print(""+i +",");
		}
		return results;
	}
	
	public static void saveImages(List<BufferedImage> images) throws Exception {		
		try {		
			for (int i=0;i<images.size();i++) {	
				File f = new File("/home/jerry/git/EasyOCR/EasyOCR/src/main/java/com/neuralnetwork/sample/util/img"+i+".png");
				ImageIO.write(images.get(i), "PNG", f);
			}
		}catch (Exception e) {
			e.printStackTrace();
		}finally {
		}
	}
	
	public static void saveImage(BufferedImage image) throws Exception {		
		try {		
			File f = new File("/home/jerry/git/EasyOCR/EasyOCR/src/main/java/com/neuralnetwork/sample/util/imgraw.png");
			ImageIO.write(image, "PNG", f);
		}catch (Exception e) {
			e.printStackTrace();
		}finally {
		}
	}
	
	public static void saveImage(BufferedImage image,String fileName) throws Exception {		
		try {		
			File f = new File("/home/jerry/git/EasyOCR/EasyOCR/src/main/java/com/neuralnetwork/sample/util/"+fileName+".png");
			ImageIO.write(image, "PNG", f);
		}catch (Exception e) {
			e.printStackTrace();
		}finally {
		}
	}
	
	public static int findStartBorder(List<Boolean> isBorders,int pos) {
		boolean contains = false;
		for (int i=pos;i<isBorders.size();i++) {
			if (!isBorders.get(i)) contains=true;
			if (!isBorders.get(i)&&contains&&i==0) return 0;
			if (!isBorders.get(i)&&contains&&i>=1) return i-1;
		}
		return -1;
	}
	
	public static int findEndBorder(List<Boolean> isBorders,int pos) {
		boolean contains = false;
		for (int i=pos;i<isBorders.size();i++) {
			if (!isBorders.get(i)) contains=true;
			if (contains&&i==isBorders.size()-1) return isBorders.size()-1;
			if (isBorders.get(i)&&contains) return i-1;
		}
		return -1;
	}
	
	public static int findStartBorder(List<Boolean> isBorders) {
		boolean contains = false;
		for (int i=0;i<isBorders.size();i++) {
			if (!isBorders.get(i)) contains=true;
			if (!isBorders.get(i)&&contains&&i==0) return 0;
			if (!isBorders.get(i)&&contains&&i>=1) return i-1;
		}
		return -1;
	}
	
	public static int findEndBorder(List<Boolean> isBorders) {
		boolean contains = false;
		for (int i=isBorders.size()-1;i>=0;i--) {
			if (!isBorders.get(i)) contains=true;
			if (!isBorders.get(i)&&contains&&i==isBorders.size()-1) return isBorders.size()-1;
			if (!isBorders.get(i)&&contains&&i<=isBorders.size()-2) return i+1;
		}
		return -1;
	}
	
	public static void main(String [] args) {
		try {
			BufferedImage bimg = ImageIO.read(new File("/home/jerry/git/EasyOCR/EasyOCR/src/main/java/com/neuralnetwork/sample/util/sample.png"));
			List<BufferedImage> images = splitImage(bimg);
			System.out.println(images.size()+":"+images.get(0).getWidth());
			saveImages(images);
			System.out.println("JerryDebug:"+recogImage(bimg));
		} catch (Exception e) {
			e.printStackTrace();
		}
	}

}
